package cn.virens.common.entity.result;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.virens.common.entity.param.PageParam;
import cn.virens.common.entity.param.PageParamUtil;
import cn.virens.common.exception.APIException;
import cn.virens.common.mapper.example.util.Util;
import cn.virens.common.utils.Assert;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.page.PageMethod;

import java.util.List;
import java.util.Map;
import java.util.function.Function;

public class PageResultQuery implements AutoCloseable {
    private final PageParam param;

    private PageResultQuery(PageParam pageParam) {
        this.param = Assert.isNull(pageParam);
    }

    /**
     * 执行分页查询
     *
     * @param <R>   返回值类型
     * @param param 参数对象
     * @param fun   查询接口
     * @return 分页对象
     * @see PageResult
     */
    public static <R> PageResult<R> selectPage(PageParam param, Function<PageResultQuery, List<R>> fun) {
        return selectPage(param, fun, list -> list);
    }

    /**
     * 执行分页查询
     *
     * @param <R>    返回值类型
     * @param <T>    过渡类型
     * @param param  参数对象
     * @param fun    查询接口
     * @param format 格式化接口
     * @return 分页对象
     * @see PageResult
     */
    public static <R, T> PageResult<R> selectPage(PageParam param, Function<PageResultQuery, List<T>> fun, Function<List<T>, List<R>> format) {
        try (PageResultQuery answer = new PageResultQuery(param)) {
            // 获取分页参数
            Integer pageSize = ObjectUtil.defaultIfNull(param.getPageSize(), 20);
            Integer pageNum = ObjectUtil.defaultIfNull(param.getPageNum(), 1);

            // 设置分页信息
            Page<Object> _page = PageMethod.startPage(pageNum, pageSize);
            _page.setCount(ObjectUtil.defaultIfNull(param.isCount(), true));
            _page.setOrderBy(StrUtil.emptyIfNull(param.getOrderBy()));

            PageResult<R> result = new PageResult<>();

            // 执行查询 并 获取查询结果中的分页信息
            PageInfo<T> pageInfo = PageInfo.of(fun.apply(answer));
            result.setList(format.apply(pageInfo.getList()));
            result.setPageSize(pageInfo.getPageSize());
            result.setPageNum(pageInfo.getPageNum());
            result.setPages(pageInfo.getPages());
            result.setTotal(pageInfo.getTotal());
            result.setSize(pageInfo.getSize());

            return result;
        }
    }

    /**
     * 获取全部参数
     *
     * @return 参数集
     * @throws APIException 普通异常
     */
    public Map<String, Object> params() throws APIException {
        return param != null ? param.getParams() : null;
    }

    /**
     * 判断参数是否存在
     *
     * @param key 参数名称
     * @return 布尔值
     * @throws APIException 普通异常
     */
    public boolean containsParam(String key) throws APIException {
        Map<String, Object> paramMap = param.getParams();
        if (paramMap != null && !paramMap.isEmpty()) {
            return Util.isNotEmpty(paramMap.get(key));
        } else {
            return false;
        }
    }

    /**
     * 获取 = 匹配参数值
     *
     * @param key 参数名称
     * @return 参数值
     */
    public Object criteriaEqual(String key) throws APIException {
        return PageParamUtil.criteriaEqual(params(), key);
    }

    /**
     * 获取 = 匹配参数值
     *
     * @param key 参数名称
     * @param def 默认值
     * @return 参数值
     */
    public Object criteriaEqual(String key, Object def) throws APIException {
        return PageParamUtil.criteriaEqual(params(), key, def);
    }

    /**
     * 获取 LIKE 匹配参数值
     *
     * @param key 参数名称
     * @return 参数值
     */
    public String criteriaLike(String key) throws APIException {
        return PageParamUtil.criteriaLike(params(), key);
    }

    /**
     * 获取 LIKE 匹配参数值
     *
     * @param key 参数名称
     * @param def 默认值
     * @return 参数值
     */
    public String criteriaLike(String key, String def) throws APIException {
        return PageParamUtil.criteriaLike(params(), key, def);
    }

    /**
     * 获取 LIKE 匹配参数值(START)
     *
     * @param key 参数名称
     * @return 参数值
     */
    public String criteriaStart(String key) throws APIException {
        return PageParamUtil.criteriaStart(params(), key);
    }

    /**
     * 获取 LIKE 匹配参数值(START)
     *
     * @param key 参数名称
     * @param def 默认值
     * @return 参数值
     */
    public String criteriaStart(String key, String def) throws APIException {
        return PageParamUtil.criteriaStart(params(), key, def);
    }

    /**
     * 获取 LIKE 匹配参数值(END)
     *
     * @param key 参数名称
     * @return 参数值
     */
    public String criteriaEnd(String key) throws APIException {
        return PageParamUtil.criteriaEnd(params(), key);
    }

    /**
     * 获取 LIKE 匹配参数值(END)
     *
     * @param key 参数名称
     * @param def 默认值
     * @return 参数值
     */
    public String criteriaEnd(String key, String def) throws APIException {
        return PageParamUtil.criteriaEnd(params(), key, def);
    }

    /**
     * 获取 IN 匹配参数值
     *
     * @param key 参数名称
     * @return 参数值
     */
    public Iterable<Object> criteriaIn(String key) throws APIException {
        return PageParamUtil.criteriaIn(params(), key);
    }

    /**
     * 获取 IN 匹配参数值
     *
     * @param key 参数名称
     * @param def 默认值
     * @return 参数值
     */
    public Iterable<Object> criteriaIn(String key, Object def) throws APIException {
        return PageParamUtil.criteriaIn(params(), key, def);
    }

    @Override
    public void close() throws APIException {
        PageMethod.clearPage();
    }
}
